package com.yc.security.authorize;

import com.yc.CustomException;
import com.yc.security.properties.SecurityProperties;
import com.yc.security.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 请求过滤器对jwt token令牌进行拦截  进行用户认证 以及权限的校验
 *
 * @author kukaha
 * @title
 * @updateTime 19:24
 * @throws
 * @return
 */
@Component
public class RedisRequestFilter extends OncePerRequestFilter {

    /**
     * 令牌头
     */
    private static final String BEARER = "Bearer ";

    /**
     * 令牌key
     */
    @Value("${jwt.header}")
    private String tokenHeader;

    /**
     * 注入对用户认证的逻辑服务
     *
     * @title
     * @author kukaha
     * @updateTime 19:26
     */
    @Autowired
    private UserDetailsService jwtUserDetailsServiceImpl;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver handlerExceptionResolver;

    /**
     * 封装，不需要过滤的list列表
     */


    @Autowired
    private SecurityProperties securityProperties;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        List<Pattern> patterns = new ArrayList<>();
        String[] urlDischarged = securityProperties.getAuthentication().getUrlDischarged();

        String url = request.getRequestURI().substring(request.getContextPath().length());
        if (url.startsWith("/") && url.length() > 1) {
            url = url.substring(1);
        }
        List<String> list = Arrays.asList(urlDischarged);
        list.forEach(f1 -> {
            patterns.add(Pattern.compile(f1));
        });
        final String requestTokenHeader = request.getHeader(tokenHeader);
        String username = null;
        String jwtToken = null;
        /**
         * JWT报文表头的格式是"Bearer token". 去除"Bearer ",直接获取token
         */
        if (requestTokenHeader != null && requestTokenHeader.startsWith(BEARER)) {
            jwtToken = requestTokenHeader.substring(7);

            String code = String.valueOf(redisTemplate.opsForValue().get(jwtToken));
            username = jwtTokenUtil.getUsernameFromToken(jwtToken);
            if (!isInclude(url,patterns)){
                if ("null".equals(code)) {
                    handlerExceptionResolver.resolveException(request,response,null,new CustomException(20023,"请重新登录"));/*token失效*/
                    return;
                }
            }

//			try {
//            username = jwtTokenUtil.getUsernameFromToken(jwtToken);
//			} catch (IllegalArgumentException e) {
//				logger.error("jwtToken非法令牌,解析失败");
//			} catch (ExpiredJwtException e) {
//				logger.error("jwtToken令牌过期");
//			} catch (SignatureException e){
//				logger.error("jwtToken签名与本地计算的签名不匹配");
//			}
        } else {
            logger.warn("jwtToken没有以Bearer 开头 已经过滤的路径");
        }
        /**
         * 验证令牌的合法性
         */
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.jwtUserDetailsServiceImpl.loadUserByUsername(username);
            /**
             * 如果令牌有效则将他手动设置到SecurityContextHolder中,以便从上下文中获取用户信息
             */
            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }

    /**
     * 是否需要过滤
     * @param url
     * @return
     */
    private boolean isInclude(String url,List<Pattern> patterns) {
        for (Pattern pattern : patterns) {
            Matcher matcher = pattern.matcher(url);
            if (matcher.matches()) {
                return true;
            }
        }
        return false;
    }

}
